#ifndef TASK_CHANNEL_H
#define TASK_CHANNEL_H

#include "../../base/noncopyable.h"
#include "../../base/Timestamp.h"

#include <functional>
#include <memory>

class EventLoop;

/**
 * 封装文件描述符和对应事件的回调函数, 用于在被poll唤醒的时候可以传递给EventLoop调用
 */
class Channel : muduo::noncopyable {
public:
    typedef std::function<void()> EventCallback;
    typedef std::function<void(Timestamp)> ReadEventCallback;
    // 对应的回调函数

    Channel(EventLoop *loop, int fd);
    // 加入事件池和对应负责的文件描述符, 自始至终只负责这个文件描述符上的事件的分发

    ~Channel();

    /**
     * 对应事件发生时调用对应回调函数, 进行一个事件的分发调用工作
     */
    void handleEvent(Timestamp receiveTime);

    /* 对应的可读, 可写, 关闭, 错误的回调函数 */
    void setReadCallback(ReadEventCallback cb) { readCallback_ = std::move(cb); }

    void setWriteCallback(EventCallback cb) { writeCallback_ = std::move(cb); }

    void setCloseCallback(EventCallback cb) { closeCallback_ = std::move(cb); }

    void setErrorCallback(EventCallback cb) { errorCallback_ = std::move(cb); }

    /**
     * 将要保存的对象保存到tie中, 防止在销毁的时候误销毁对应对象
     */
    void tie(const std::shared_ptr<void> &);

    /**
     * 返回对应负责的文件描述符
     */
    int fd() const { return fd_; }

    /**
     * 返回要监视的事件
     */
    int events() const { return events_; }

    /* 发生的事件 */
    void set_revents(int revt) { revents_ = revt; }

    /**
     * 设定用户是否不关心任何事件
     */
    bool isNoneEvent() const { return events_ == kNoneEvent; }

    /* 设定用户关心的事件 */
    void enableReading() {
        events_ |= kReadEvent;
        update();
        // TODO: 注意在每次设定完成用户关心的事件之后都会直接将channel添加到loop的IO多路复用的监听列表中
    }

    void disableReading() {
        events_ &= ~kReadEvent;
        update();
    }

    void enableWriting() {
        events_ |= kWriteEvent;
        update();
    }

    void disableWriting() {
        events_ &= ~kWriteEvent;
        update();
    }

    void disableAll() {
        events_ = kNoneEvent;
        update();
    }

    /**
     * 返回是否关心可读 | 可写事件
     */
    bool isWriting() const { return events_ & kWriteEvent; }

    bool isReading() const { return events_ & kReadEvent; }

    /**
     * 获取index, 用于在loop的事件列表中定位
     */
    int index() const { return index_; }

    void set_index(int index) { index_ = index; }

    EventLoop *ownerLoop() { return loop_; }

    /**
     * 移除自身从loop的监听循环中, 这里会调用到loop_的removeChannel
     * 这里应该由TcpConnection的连接销毁函数调用
     */
    void remove();

    /**
     * 将当前发生的事件转化为string删除
     * @return
     */
    string reventsToString() const;

    /**
     * 将关心的事件转化为string输出
     * @return
     */
    string eventsToString() const;

private:
    static string eventsToString(int fd, int ev);

    void update();

    void handleEventWithGuard(Timestamp receiveTime);

    static const int kNoneEvent;
    static const int kReadEvent;
    static const int kWriteEvent;

    EventLoop *loop_;
    const int fd_;
    int events_;
    // 这个Channel类关心的事件
    int revents_;
    // 当前活动的事件
    int index_;
    // 用于Poller中的

    std::weak_ptr<void> tie_;
    bool tied_;
    // TODO: 提醒下, 后面研究下这个保存

    bool eventHandling_;
    // 当前是否在处理分发对应的事件
    bool addedToLoop_;
    // 表明是否被添加到Loop中, 在插入的时候被设置为true,
    // remove的时候被设置为false

    /* 各种事件的回调函数封装 */
    ReadEventCallback readCallback_;
    EventCallback writeCallback_;
    EventCallback closeCallback_;
    EventCallback errorCallback_;
};

#endif //TASK_CHANNEL_H
